using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ResourcesManager : Singleton<ResourcesManager>
{
    public bool LoadFormAssetBundle = false;
    
    //缓存使用的资源列表
    public Dictionary<uint, ResourceItem> AssetDic { get; set; } = new Dictionary<uint, ResourceItem>();

    //缓存 引用 计数 为零的 资源，达到缓存最大的时候释放这个列表里最早没用的资源
    protected CMapList<ResourceItem> NoRefrenceAssetMapList = new CMapList<ResourceItem>();

    /// <summary>
    /// 同步资源加载   外部直接调用   仅加载不用实例化的资源
    /// </summary>
    /// <param name="path"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T LoadResource<T>(string path) where T : UnityEngine.Object
    {
        if (string.IsNullOrEmpty(path))
        {
            return null;
        }

        uint crc = CRC32.GetCRC32(path);
        ResourceItem item = GetCacheResourceItem(crc);
        if (item != null)
        {
            return item.Obj as T;
        }
        T obj = null;
#if UNITY_EDITOR
        if (!LoadFormAssetBundle)
        {
            obj = LoadAssetByEditor<T>(path);
            item = AssetBundleManager.Instance.FindResourceItem(crc);
        }
#endif
        if (obj == null)
        {
            item = AssetBundleManager.Instance.LoadResourceAssetBundle(crc);
            if (item != null && item.AssetBundle != null)
            {
                obj = item.AssetBundle.LoadAsset<T>(item.AssetName);
            }
        }

        CacheResource(path,ref item, crc, obj);
        
        return obj;
    }

    void CacheResource(string path, ref ResourceItem item, uint crc, Object obj, int addRefCount = 1)
    {
        if (item == null)
        {
            Debug.LogError("资源 为 空 " + path);
        }
        if (obj == null)
        {
            Debug.LogError("资源 加载 失败 " + path);
        }

        item.Obj = obj;
        item.Guid = obj.GetInstanceID();
        item.LastUseTime = Time.realtimeSinceStartup;
        item.RefCount += addRefCount;
        ResourceItem oldItem = null;
        if (AssetDic.TryGetValue(item.Crc, out oldItem))
        {
            AssetDic[item.Crc] = item;
        }
        else
        {
            AssetDic.Add(item.Crc, item);
        }
    }
    
#if UNITY_EDITOR
    protected T LoadAssetByEditor<T>(string path) where T : UnityEngine.Object
    {
        return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
    }
#endif
    
    ResourceItem GetCacheResourceItem(uint crc ,int addRefCount = 1)
    {
        ResourceItem item = null;
        if (AssetDic.TryGetValue(crc, out item) ) 
        {
            if (item != null)
            {
                item.RefCount += addRefCount;
                item.LastUseTime = Time.realtimeSinceStartup;

                // if (item.RefCount <= 1)
                // {
                //     NoRefrenceAssetMapList.Remove(item);
                // }
            }
        }

        return item;
    }


}

public class DoubleLinkedListNode<T> where T : class, new()
{
    // 前一个节点
    public DoubleLinkedListNode<T> Prev = null;

    // 后一个节点
    public DoubleLinkedListNode<T> Next = null;

    // 当前节点
    public T Current = null;
}

public class DoubleLinedList<T> where T : class, new()
{
    //表头
    public DoubleLinkedListNode<T> Head = null;
    
    //表尾
    public DoubleLinkedListNode<T> Tail = null;

    //双向链表 表 类对象池
    protected ClassObjectPool<DoubleLinkedListNode<T>> DoubleLinkNodePool = ObjectManager.Instance.GetOrCreatClassPool<DoubleLinkedListNode<T>>(500);

    //个数
    private int _count = 0;
    public int Count => _count;

    /// <summary>
    /// 添加一个节点到头部
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToHeader(T t)
    {
        DoubleLinkedListNode<T> plist = DoubleLinkNodePool.Spawn(true);
        plist.Next = null;
        plist.Prev = null;
        plist.Current = t;
        return AddToHeader(plist);
    }

    /// <summary>
    /// 添加一个节点到头部
    /// </summary>
    /// <param name="pNode"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToHeader(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null)
        {
            return null;
        }

        pNode.Prev = null;
        if (Head == null)
        {
            Head = Tail = pNode;
        }
        else
        {
            pNode.Next = Head;
            Head.Prev = pNode;
            Head = pNode;
        }

        _count++;
        return Head;
    }

    /// <summary>
    /// 添加节点到尾部
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToTail(T t)
    {
        DoubleLinkedListNode<T> pList = DoubleLinkNodePool.Spawn(true);
        pList.Next = null;
        pList.Prev = null;
        pList.Current = null;
        return AddToTail(pList);
    }

    /// <summary>
    /// 添加节点到尾部
    /// </summary>
    /// <param name="pNode"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToTail(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null)
        {
            return null;
        }

        pNode.Next = null;
        if (Tail == null)
        {
            Head = Tail = pNode;
        }
        else
        {
            pNode.Prev = Tail;
            Tail.Next = pNode;
            Tail = pNode;
        }

        _count++;
        return Tail;
    }

    /// <summary>
    /// 移除某个节点
    /// </summary>
    /// <param name="pNode"></param>
    public void RemoveNode(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null)
        {
            return;
        }

        if (pNode == Head)
        {
            Head = pNode.Next;
        }
        if (pNode == Tail)
        {
            Tail = pNode.Prev;
        }

        if (pNode.Prev != null)
        {
            pNode.Prev.Next = pNode.Next;
        }

        if (pNode.Next != null)
        {
            pNode.Next.Prev = pNode.Prev;
        }

        pNode.Next = pNode.Prev = null;
        pNode.Current = null;

        DoubleLinkNodePool.Recycle(pNode);
        _count--;
    }

    /// <summary>
    /// 吧某个节点移动到头部
    /// </summary>
    /// <param name="pNode"></param>
    public void MoveToHead(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null || pNode == Head)
        {
            return;
        }

        if (pNode.Prev == null && pNode.Next == null)
        {
            return;
        }

        if (pNode == Tail)
        {
            Tail = pNode.Prev;
        }

        if (pNode.Prev != null)
        {
            pNode.Prev.Next = pNode.Next;
        }

        if (pNode.Next != null)
        {
            pNode.Next.Prev = pNode.Prev;
        }

        pNode.Prev = null;
        pNode.Next = Head;
        Head.Prev = pNode;
        Head = pNode;
        
        if (Tail == null)
        {
            Tail = Head;
        }
    }

}

public class CMapList<T> where T : class, new()
{
    public DoubleLinedList<T> DLink = new DoubleLinedList<T>();

    public Dictionary<T, DoubleLinkedListNode<T>> FindMap = new Dictionary<T, DoubleLinkedListNode<T>>();

    ~CMapList()
    {
        Clear();
    }
    
    public void Clear()
    {
        while (DLink.Tail != null)
        {
            Remove(DLink.Tail.Current);
        }
    }
    
    /// <summary>
    /// 插入节点到表头
    /// </summary>
    /// <param name="t"></param>
    public void InsertToHead(T t)
    {
        DoubleLinkedListNode<T> node = null;
        if (FindMap.TryGetValue(t,out node) && node != null)
        {
            DLink.AddToHeader(node);
            return;
        }

        DLink.AddToHeader(t);
        FindMap.Add(t, DLink.Head);
    }

    /// <summary>
    /// 从表尾弹出 节点
    /// </summary>
    public void Pop()
    {
        if (DLink.Tail != null)
        {
            Remove(DLink.Tail.Current);
        }
    }

    /// <summary>
    /// 删除节点 最后一个
    /// </summary>
    /// <param name="t"></param>
    public void Remove(T t)
    {
        DoubleLinkedListNode<T> node = null;
        if (!FindMap.TryGetValue(t,out node) || node == null)
        {
            return;
        }

        DLink.RemoveNode(node);
        FindMap.Remove(t);
    }

    /// <summary>
    /// 获取尾部节点
    /// </summary>
    /// <returns></returns>
    public T Back()
    {
        return DLink.Tail?.Current;
    }

    public int Size()
    {
        return FindMap.Count;
    }

    /// <summary>
    /// 查找是否存在这个节点
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public bool Find(T t)
    {
        DoubleLinkedListNode<T> node = null;

        if (!FindMap.TryGetValue(t,out node) || node == null)
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// 移动节点 到头部
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public bool Refresh(T t)
    {
        DoubleLinkedListNode<T> node = null;

        if (!FindMap.TryGetValue(t,out node) || node == null)
        {
            return false;
        }
        
        DLink.MoveToHead(node);
        return true;
    }
}